//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <core.h>
#include <crust.h>

#define DECL_SYS_PROXY_ENTRY()          \
    __asm__(                            \
        ".text;"                        \
        ".align 4;"                     \
        ".globl _SysProxyEntry;"        \
        "_SysProxyEntry:"               \
        ".intel_syntax;"                \
        "push   esp;"                   \
        "mov    eax, dword ptr [esp + 8];" \
        "call   dword ptr [eax + 4];"   \
        "ret    0x4;"                   \
        ".att_syntax;"                  \
    )

#define SYS_PROXY_RET_OFFSET    9

EXTERN_C void SysProxyEntry(void);
DECL_SYS_PROXY_ENTRY();

STATIC DECL_CODEINIT void *NewProxyEntryTable();

EXTERN DECL_CODEINIT bool_t CDECL InitProxyEntryTable()
{
    assert(0 == g_initPageDir[PD_INDEX(PROXY_ENTRY_BASE)].uValue);

    PageTabEntry *pPageTab = AllocPageTable();
    if (NULL == pPageTab) return FALSE;

    void *pProxyEntryTable = NewProxyEntryTable();
    if (NULL == pProxyEntryTable) {
        DzFreeKernelPage(pPageTab);
        return FALSE;
    }

    memset(pPageTab, 0, c_uSizeOfPageTab);
    pPageTab[PT_INDEX(PROXY_ENTRY_BASE)].uValue =
        PHYSADDR(pProxyEntryTable) +
        PageEntryFlag_Present +
        PageEntryFlag_User;

    g_initPageDir[PD_INDEX(PROXY_ENTRY_BASE)].uValue =
        PHYSADDR(pPageTab) + PageEntryFlag_Present + PageEntryFlag_User;

    FlushTlb((virtaddr_t)PROXY_ENTRY_BASE);

    return TRUE;
}

STATIC DECL_CODEINIT void *NewProxyEntryTable()
{
    void *pProxyEntryTable = (char *)DzAllocKernelPage();
    if (NULL == pProxyEntryTable) return NULL;

    char *p = (char *)pProxyEntryTable;
    for (int n = 0; n < PROXY_ENTRY_NUM; n++) {
        memcpy(p, (void *)&SysProxyEntry, PROXY_ENTRY_SIZE);
        *(Int16 *)&(p[SYS_PROXY_RET_OFFSET]) = ((n + 1) << 2);
        p += PROXY_ENTRY_SIZE;
    }

    return pProxyEntryTable;
}
